package com.amar.dtadmin.apidoc.action;

import com.amar.dtadmin.apidoc.util.PsiAnnotationUtil;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;

/**
 * @author xiaoshiqiang
 * @since 2025/2/12
 */
public class DtAdminApiDocActionGroup extends DefaultActionGroup {
    @Override
    public void update(@NotNull AnActionEvent e) {
        super.update(e);
        e.getPresentation().setEnabledAndVisible(getSelectedPisData(e).isValid());
    }

    @Override
    public @NotNull ActionUpdateThread getActionUpdateThread() {
        return ActionUpdateThread.BGT;
    }

    public static SelectedPsiData getSelectedPisData(AnActionEvent e) {
        PsiAnnotation apiAnnotation = getTargetAnnotation(e);
        PsiClass apiClass = PsiTreeUtil.getParentOfType(apiAnnotation, PsiClass.class);
        Pair<PsiClass, PsiClass> apiParameter = getGenericParameterClasses(apiClass);
        return new SelectedPsiData(apiAnnotation, apiClass, apiParameter.getLeft(), apiParameter.getRight(), e.getProject());
    }

    /**
     * 获取光标位置的 PsiAnnotation
     */
    public static PsiAnnotation getTargetAnnotation(AnActionEvent event) {
        Project project = event.getProject();
        Editor editor = event.getData(CommonDataKeys.EDITOR);
        PsiFile psiFile = event.getData(CommonDataKeys.PSI_FILE);

        if (psiFile == null && editor != null && project != null) {
            psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
        }

        if (project == null || editor == null || psiFile == null) {
            return null;
        }

        Document document = editor.getDocument();
        int lineNumber = document.getLineNumber(editor.getCaretModel().getOffset());
        int lineStartOffset = document.getLineStartOffset(lineNumber);
        int lineEndOffset = document.getLineEndOffset(lineNumber);
        PsiAnnotation annotation = PsiTreeUtil.findElementOfClassAtRange(psiFile, lineStartOffset, lineEndOffset, PsiAnnotation.class);
        if (annotation != null && "com.amarsoft.hub.api.annotation.ApiService".equals(annotation.getQualifiedName())) {
            return annotation;
        }
        return null;
    }

    public static Pair<PsiClass, PsiClass> getGenericParameterClasses(PsiClass psiClass) {
        if (psiClass == null) {
            return Pair.of(null, null);
        }

        PsiClassType[] superTypes = psiClass.getSuperTypes();
        for (PsiClassType superType : superTypes) {
            PsiType[] typeParameters = superType.getParameters();
            if (typeParameters.length >= 2) {
                PsiClass inputClass = PsiUtil.resolveClassInType(typeParameters[0]);
                PsiClass outputClass = PsiUtil.resolveClassInType(typeParameters[1]);

                if (inputClass != null && outputClass != null) {
                    return Pair.of(inputClass, outputClass);
                }
            }
        }
        return Pair.of(null, null);
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class SelectedPsiData {
        /**
         * 光标所在的的ApiService注解
         */
        private PsiAnnotation apiAnnotation;

        /**
         * Api接口对应的class
         */
        private PsiClass apiClass;

        /**
         * 接口入参class
         */
        private PsiClass inputClass;

        /**
         * 接口出参class
         */
        private PsiClass outputClass;

        private Project project;

        /**
         * 光标所选对象，是否为合法Api接口
         *
         * @return boolean
         */
        public boolean isValid() {
            return Objects.nonNull(apiAnnotation)
                    && Objects.nonNull(apiClass)
                    && Objects.nonNull(inputClass)
                    && Objects.nonNull(outputClass)
                    && Objects.nonNull(project);
        }

        public ApiInfo getApiInfo() {
            ApiInfo apiInfo = new ApiInfo();
            if (apiAnnotation != null) {
                apiInfo.setApi(PsiAnnotationUtil.getAnnotationValue(apiAnnotation, "name"));
                apiInfo.setGroup(PsiAnnotationUtil.getAnnotationValue(apiAnnotation, "group"));
                apiInfo.setName(PsiAnnotationUtil.getAnnotationValue(apiAnnotation, "desc"));
                apiInfo.setInputClass(inputClass);
                apiInfo.setOutputClass(outputClass);
            }
            return apiInfo;
        }
    }

    @Data
    public static class ApiInfo {
        /**
         * 接口号
         */
        private String api;

        /**
         * 接口所属组
         */
        private String group;

        /**
         * 接口名称、描述
         */
        private String name;

        /**
         * 接口所属组Id
         */
        private String groupId;

        /**
         * 接口分组级别
         */
        private String groupLevel;

        /**
         * 接口入参类
         */
        private PsiClass inputClass;

        /**
         * 接口出参类
         */
        private PsiClass outputClass;
    }
}
